/*
PARI/GP scripts related to the normal error distribution
=============================================================
File: NormalErrorFunctions.txt    
Link: https://oeis.org/wiki/File:NormalErrorFunctions.txt
=============================================================
*/


NormalErrorDf(x) = exp(-x*x/2.0)/sqrt(2.0*Pi);
/* ----------------------------------------------------------
  Returns the value of the normal (Gaussian) probability
  density function with standard deviation sigma=1 and mean 0.
  Its domain is (-inf,+inf), mapped on (0,1/sqrt(2*Pi)).
---------------------------------------------------------- */

NormalErrorCdf(x) = (2.0-erfc(x/sqrt(2.0)))/2.0;
/* ----------------------------------------------------------
  Returns the value of the normal (Gaussian) cumulative
  distribution function with standard deviation sigma=1,
  centered at 0.

  This function is sometimes also denoted as Phi(x).
  It accepts t_REAL or t_COMPLEX arguments. In the t_REAL
  case, its domain is (-inf,+inf), mapped on (0,1).

  As all cdf's, the function tends to 0.0 at -infinity and
  to +1.0 at plus infinity, and is monotonously increasing.

  One can use it to calculate the unilateral and bilateral
  normal error distribution percentiles (in units of sigma),
  such as the 75% percentile (A092678) obtained by
    p75 = solve(x=-10.0,10.0,NormalErrorCdf(x)-0.75).
  In these cases, however, the next function,
  NormalErrorPercentile(p), is recommended.
---------------------------------------------------------- */

NormalErrorPercentile(p) =
/* ----------------------------------------------------------
  The inverse of NormalErrorCdf(x); it returns the value of
  x such that p = NormalErrorCdf(x). Often called probit(p).
  Its t_REAL domain is (0,1) and it maps on (-inf,+inf).
  Care has been taken to handle properly the cases where p
  is very close to the domain limits. The purpose here was
  not speed (so far).
---------------------------------------------------------- */
{
  my(x,y,xlim);
  if (type(p)!="t_REAL", error("Argument must be t_REAL"));
  if (p < 0.5, y=1.0-p, y=p);
  if (y >= 1.0, error("DOMAIN: argument outside of (0,1)"));
  xlim = 10.0;
  while (1, \\ Bracket the solution
    if (NormalErrorCdf(xlim)>y, break);
    xlim *= 2.0;
  );
  x = solve(x=-xlim,xlim,NormalErrorCdf(x)-y);
  if (p < 0.5, -x, x);
}

RngNormal(mean,stddev) = 
/* ----------------------------------------------------------
  Random numbers generator for the normal distribution
  with a given mean and standard deviation.
  Full default(realprecision) is applied.
---------------------------------------------------------- */
{
  my(n=10^default(realprecision),eps=10.0/n);
  my(x,y,r=0.0);
  while ((r<eps)||(r>1.0),
    x = 2.0*random(n)/n-1.0;
    y = 2.0*random(n)/n-1.0;
    r = x*x+y*y;
  );
  r = x*sqrt(-2.0*log(r)/r);
  mean+stddev*r;
}


/*
=============================================================
   The following functions complement PARI library:
=============================================================
*/


Erf(z) = 1.0-erfc(z);
/* ----------------------------------------------------------
  Error function for real|complex arguments. 
---------------------------------------------------------- */

Erfi(z) = -I*(1.0-erfc(I*z));
/* ----------------------------------------------------------
  Imaginary error function for real|complex arguments. 
---------------------------------------------------------- */

Fadeevaw(z) = exp(-z*z)*erfc(-I*z);
/* ----------------------------------------------------------
  Fadeeva w(z) function for any real|complex arguments. 
---------------------------------------------------------- */

DErf(z) = 2.0*exp(-z*z)/sqrt(Pi);
/* ----------------------------------------------------------
  First derivative of the error function
---------------------------------------------------------- */

Derfc(z) = -2.0*exp(-z*z)/sqrt(Pi);
/* ----------------------------------------------------------
  First derivative of the complementary error function
---------------------------------------------------------- */

ADErf(z) = z*(1.0-erfc(z)) + exp(-z*z)/sqrt(Pi);
/* ----------------------------------------------------------
  Anti-derivative of the error function
---------------------------------------------------------- */

ADerfc(z) = z*erfc(z) - exp(-z*z)/sqrt(Pi);
/* ----------------------------------------------------------
  Anti-derivative of the complementary error function
---------------------------------------------------------- */

Dawson(z) = 0.5*sqrt(Pi)*exp(-z*z)*Erfi(z);
/* ----------------------------------------------------------
  The Dawson integral for real|complex arguments.
  The returned value is of type t_COMPLEX
---------------------------------------------------------- */

DDawson(z) = 1.0 - 2*z*Dawson(z);
/* ----------------------------------------------------------
  First derivative of the Dawson integral.
  The returned value is of type t_COMPLEX
---------------------------------------------------------- */

D2Dawson(z) = -2.0*(z + (1.0-2.0*z*z)*Dawson(z));
/* ----------------------------------------------------------
  Second derivative of the Dawson integral.
  The returned value is of type t_COMPLEX
---------------------------------------------------------- */

/*
=============================================================
  References:
    http://en.wikipedia.org/wiki/Error_function
    http://dx.doi.org/10.3247/SL4Soft12.001
    http://mathworld.wolfram.com/DawsonsIntegral.html

  Contributed to OEIS Wiki by Stanislav Sykora
=============================================================
*/

